// literals.cpp
// Customizer_Base
// Protea Customizer/Customizer Pro / Business Logic for managing literals
// Copyright (C) 2003, 2004, 2005 eXegeSys, Inc.
// Copyright (C) 2008 Bruce A. James
//
// This program is part of the Protea Project.
//
// The Protea Project is free software; you can redistribute it and/or modify it 
// under the terms of the GNU General Public License as published by the 
// Free Software Foundation, either version 3 of the License, or (at your 
// option) any later version.
//
// The Protea Project is distributed in the hope that it will be useful, but 
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
// for more details.
// 
// You should have received a copy of the GNU General Public License along 
// with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// Please send correspondence to:
//
// theproteaproject@gmail.com
//

#include "base_setup.h"

// LITERAL_DEFN Subtransactions
//
//////////////////////////////////////////////////////////////////////////////

//@ SEC 3
//@ CHA Literal Defn Verify
//@ COD LiteralDefnVerify
//@ TAB LITERAL_DEFN Read
//@ GEN Use LiteralDefnVerify to verify literal definition record

void LiteralDefnVerify( XCBuffer* buf, XCTransactionVars* vars, verify_type verify_mode, bool pro_mode, XCBuffer* orig ) 
{
	TRANS_INFUNC( LiteralDefnVerify );

	//@ If verifying an ADD transaction,
	if (verify_mode == VERIFY_ADD) {
		//@ GRS

		//@ SUB ValidateName to check for a valid name
		ValidateName( FLD_LITERAL_NAME, vars->buffer, ERR_LITERAL, vars );

		//@ UTL LookupNumberFromName to convert literal name into a literal number
		//@ ERR C (ALREADY_EXISTS) Literal already exists
		if ( LookupNumberFromName( vars, vars->buffer, buf, FLD_LITERAL_NUMBER, FLD_LITERAL_NAME, FMT_LITERAL_DEFN ))
			vars->Errors->Add( ERR_ALREADY_EXISTS, SEV_CRITICAL, FLD_LITERAL_NAME, 1, ERR_LITERAL );

		//@ GRE
	} else {
		//@ GRS
		
		//@ SUB LiteralDefnRetrieve to verify that we do have a literal with this name
		//@ ERR E (DOESNT_EXIST) Literal doesn't exist
		if ( ! LookupNumberFromName( vars, vars->buffer, buf, FLD_LITERAL_NUMBER, FLD_LITERAL_NAME, FMT_LITERAL_DEFN ) || 
			!LiteralDefnRetrieve( buf, vars ))
			vars->Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_LITERAL_NAME, 1, ERR_LITERAL );

		//@ Check system/user level settings if not in pro mode
		if (!pro_mode && verify_mode != VERIFY_REVIEW) {
			//@ GRS

			//@ If a system object, error:
			//@ ERR C (CHANGE_CRITICAL_OBJECT)
			if (buf->GetField( FLD_SYSTEM_OBJECT )->GetBool())
				vars->Errors->Add( ERR_CHANGE_CRITICAL_OBJECT, SEV_CRITICAL );

			//@ GRE
		};

		//@ GRE
	};
	TRANS_OUTFUNC();
};

//@ SEC 3
//@ CHA Literal Defn Add
//@ COD LiteralDefnAdd
//@ TAB LITERAL_DEFN Write
//@ GEN Use LiteralDefnAdd to add a literal definition record

void LiteralDefnAdd( XCBuffer* buf, XCTransactionVars* vars, bool pro_mode ) 
{
	TRANS_INFUNC( LiteralDefnAdd );

	XCDBStatement* stmt = NULL;
	XCBuffer* temp = NULL;
	XCSQLGen* query = vars->query;

	long last_number = 0;

	//@ Determine the next available literal number
	temp = App->CreateBuffer( FMT_LITERAL_DEFN );
	try {
		XCOrder ord;
		XCCompare comp;
		bool found = false;

		query->MakeSELECT( temp );
		query->AddWHERE( buf->GetField( FLD_APPL_NBR ), &comp );
		query->AddORDERBY( FLD_LITERAL_NUMBER, &ord );
		stmt = vars->dbtxn->ExecuteSQL( query );
		while ( !found && !stmt->Eof() )
		{
			long value = temp->GetField( FLD_LITERAL_NUMBER )->GetLong( true );
			if ( value != last_number + 1 )
			{
				// we found a blank space
				found = true;
				last_number++;
			}
			else
			{
				last_number = value;
				stmt->MoveNext();
			};
		};

		// Cleanup now
		App->CleanupObjects( 2, &temp, &stmt );

		if (!found)
			last_number++;
		buf->GetField( FLD_LITERAL_NUMBER )->SetLong( last_number );

		// Set the literal length
		buf->GetField( FLD_LITERAL_LENGTH )->SetLong( strlen( buf->GetField( FLD_LITERAL )->GetStringPtr() ) );

	} catch( ... ) {
		App->CleanupObjects( 2, &temp, &stmt );
		throw;
	};

	//@ Set the SYSTEM_OBJECT field accordingly
	buf->GetField( FLD_SYSTEM_OBJECT )->SetBool( pro_mode );

	//@ Add the literal record
	query->MakeFull( SQL_STMT_INSERT, buf );
	vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );

	TRANS_OUTFUNC();
};




//@ SEC 3
//@ CHA Literal Defn Change
//@ COD LiteralDefnChange
//@ TAB LITERAL_DEFN Write
void LiteralDefnChange( XCBuffer* input, XCBuffer* orig, XCTransactionVars* vars ) {
	XCSQLGen* query = vars->query;

	TRANS_INFUNC( FieldDescChange );

	//@ Issue update statement
	query->MakeFull( SQL_STMT_UPDATE, input, orig );
	vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );

	TRANS_OUTFUNC();
};




//@ SEC 3
//@ CHA Literal Defn Delete
//@ COD LiteralDefnDelete
//@ TAB LITERAL_DEFN Write
//@ GEN Use to delete literal definition records
void LiteralDefnDelete( XCBuffer* buf, XCTransactionVars* vars ) 
{
	TRANS_INFUNC( LiteralDefnDelete );

	XCSQLGen* query = vars->query;

	//@ Delete the literal definition record
	query->MakeFull( SQL_STMT_DELETE, buf );
	vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );

	//@ Delete all LITERAL_VALUES records associated with this record
	XCBuffer* Literal_Value = vars->myapp->CreateBuffer( FMT_LITERAL_VALUES );
	try {
		Literal_Value->MoveCorresponding( buf, NULL );
		query->MakeDELETE( Literal_Value );
		query->AddWHERE( 2, 
			Literal_Value->GetField( FLD_APPL_NBR ), 
			Literal_Value->GetField( FLD_LITERAL_NUMBER ));
		vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );
	} catch( ... ) {
		Literal_Value->Release();
		throw;
	};
	Literal_Value->Release();


	//@ Delete this literal from all LIT_GROUPS
	XCBuffer* Lit_Relate = vars->myapp->CreateBuffer( FMT_LIT_RELATE );
	try {
		Lit_Relate->MoveCorresponding( buf, NULL );
		query->MakeDELETE( Lit_Relate );
		query->AddWHERE( 2, 
			Lit_Relate->GetField( FLD_APPL_NBR ), 
			Lit_Relate->GetField( FLD_LITERAL_NUMBER ));
		vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );
	} catch( ... ) {
		Lit_Relate->Release();
		throw;
	};
	Lit_Relate->Release();

	TRANS_OUTFUNC();
};



//@ SEC 3
//@ CHA Literal Defn Delete All
//@ COD LiteralDefnDeleteAll
//@ TAB LITERAL_DEFN Write
//@ GEN Use to delete all literal definition records
void LiteralDefnDeleteAll( XCBuffer* buf, XCTransactionVars* vars ) 
{
	TRANS_INFUNC( LiteralDefnDeleteAll );

	XCSQLGen* query = vars->query;
	XCBuffer* lits = App->CreateBuffer( FMT_LITERAL_DEFN, false );

	//@ Delete the literal definition records
	try {
		query->MakeDELETE( lits );
		query->AddWHERE( 1, buf->GetField( FLD_APPL_NBR ) );
		vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );
		lits->Release();
	} catch( ... ) {
		lits->Release();
		throw;
	};

	TRANS_OUTFUNC();
};



//@ SEC 3
//@ CHA Literal Defn Retrieve
//@ COD LiteralDefnRetrieve
//@ TAB LITERAL_DEFN Read
//@ GEN Use LiteralDefnRetrieve to retrieve literal definition records

bool LiteralDefnRetrieve( XCBuffer* buf, XCTransactionVars* vars ) 
{
	TRANS_INFUNC( LiteralDefnRetrieve );

	bool result;
	XCDBStatement* stmt = NULL;
	XCSQLGen* query = vars->query;

	try {
		query->MakeFull( SQL_STMT_SELECT, buf );
		stmt = vars->dbtxn->ExecuteSQL( query );
		result = (!stmt->Eof());
	} catch( ... ) {
		App->CleanupObjects( 1, &stmt );
		throw;
	};
	App->CleanupObjects( 1, &stmt );

	TRANS_OUTFUNCRET( result );
};



//////////////////////////////////////////////////////////////////////////////
//
// Internal functions
//
//////////////////////////////////////////////////////////////////////////////

void AddLiteralInternal( XCTransactionVars* vars, bool pro_mode ) {
	XCBuffer* literal_defn = NULL;

	//@ Check for blank LITERAL_NAME
	XCField* lit_name = vars->buffer->GetField( FLD_LITERAL_NAME );
	if (lit_name->IsBlank())
		vars->Errors->Add( ERR_IS_BLANK, SEV_CRITICAL, FLD_LITERAL_NAME, 1, lit_name );

	//@ Create Literal Defn buffer
	literal_defn = vars->myapp->CreateBuffer( FMT_LITERAL_DEFN );

	try {
		//@ Move screen info to transaction buffer
		literal_defn->MoveCorresponding( vars->buffer, vars->Errors );
		vars->Errors->Check();

		//@ SUB LiteralDefnVerify to verify that application can be added
		LiteralDefnVerify( literal_defn, vars, VERIFY_ADD, pro_mode );

		//@ Check for errors
		vars->Errors->Check();

		//@ SUB LiteralDefnAdd to add the new application
		LiteralDefnAdd( literal_defn, vars, pro_mode );

		vars->buffer->MoveCorresponding( literal_defn, vars->Errors );
		vars->myapp->TransResponse( vars->result, vars->buffer, TRANS_HEADER_TYPE );
	} catch( ... ) {
		literal_defn->Release();
		throw;
	};
	literal_defn->Release();
};



bool ChgLiteralInternal( XCTransactionVars* vars, bool pro_mode ) {
	XCBuffer* literal_defn = NULL;
	XCBuffer* OrigBuf = NULL;
	bool result = false;

	try {
		bool ReviewOnly = vars->buffer->IsBlank( 1, FLD_LITERAL_NAME );

		//@ Check for blank LITERAL_NAME
		XCField* lit_name = vars->buffer->GetField( FLD_LITERAL_NAME );
		if (lit_name->IsBlank())
			vars->Errors->Add( ERR_IS_BLANK, SEV_CRITICAL, FLD_LITERAL_NAME, 1, lit_name );

		//@ Create Literal Defn buffer
		literal_defn = vars->myapp->CreateBuffer( FMT_LITERAL_DEFN );

		//@ Move screen info to transaction buffer
		literal_defn->MoveCorresponding( vars->buffer, vars->Errors );
		vars->Errors->Check();

		OrigBuf = literal_defn->Copy();

		//@ SUB LiteralDefnVerify to verify that application can be added
		LiteralDefnVerify( literal_defn, vars, ReviewOnly?VERIFY_REVIEW:VERIFY_CHANGE, pro_mode, OrigBuf );

		//@ Check for errors
		vars->Errors->Check();

		//@ If not reviewing, submit the change
		if (!ReviewOnly) {
			//@ GRS Else
			//@ SUB LiteralDefnChange change field record
			OrigBuf->MoveField( literal_defn, FLD_LITERAL_NUMBER );

			literal_defn->DebugDump();
			OrigBuf->DebugDump();
			LiteralDefnChange( OrigBuf, literal_defn, vars );
			result = true;
			//@ GRE
		};

		//@ Send back result buffer
		if (ReviewOnly)
			vars->buffer->MoveCorresponding( literal_defn, vars->Errors );
		else
			vars->buffer->MoveCorresponding( OrigBuf, vars->Errors );
		vars->myapp->TransResponse( vars->result, vars->buffer, TRANS_HEADER_TYPE );
	} catch( ... ) {
		vars->myapp->CleanupObjects( 2, &literal_defn, &OrigBuf );
		throw;
	};
	vars->myapp->CleanupObjects( 2, &literal_defn, &OrigBuf );
	return result;
};



void DelLiteralInternal( XCTransactionVars* vars, bool pro_mode ) {
	XCBuffer* TransBuf = NULL;

	//@ Create literal buffer
	TransBuf = vars->myapp->CreateBuffer( FMT_LITERAL_DEFN, false );

	try {
		//@ Move screen info to transaction buffer
		TransBuf->MoveCorresponding( vars->buffer, vars->Errors );
		vars->Errors->Check();

		//@ SUB LiteralDefnVerify to verify that record can be deleted
		LiteralDefnVerify( TransBuf, vars, VERIFY_DELETE, pro_mode );

		vars->Errors->Check();

		//@ SUB LiteralDefnDelete to delete the record.
		LiteralDefnDelete( TransBuf, vars );
	} catch( ... ) {
		TransBuf->Release();
		throw;
	};
	TransBuf->Release();
};
